/*
 * Developer : Jack Matthews
 * Email: developer@droidprofessor.com
 * 
 * Copyright (C) 2010 http://droidprofessor.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.droidprofessor.android.library.phonelicenses;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Locale;

import org.apache.http.Header;
import org.apache.http.HeaderIterator;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.NameValuePair;
import org.apache.http.ProtocolVersion;
import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIUtils;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;

import android.os.Handler;
import android.util.Log;

/**
 * Allows the downloading of files easily in a Thread controlled fashion.
 * 
 * 
 * @author Jack Matthews
 * 
 */
class HttpUrlRequest extends Thread {

	private static final String TAG = "HttpUrlRequest";
	private static final HttpClient httpClient;
	


	static {
		HttpParams params = new BasicHttpParams();
		HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
		HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
	    HttpProtocolParams.setUseExpectContinue(params, false);  
	    HttpConnectionParams.setConnectionTimeout(params, 10000);
	    HttpConnectionParams.setSoTimeout(params, 30000);
	    ConnManagerParams.setMaxTotalConnections(params, 100);
	    ConnManagerParams.setTimeout(params, 30000);
	    
		SchemeRegistry registry = new SchemeRegistry();
		registry.register(new Scheme("http",PlainSocketFactory.getSocketFactory(), 80));
		registry.register(new Scheme("https",PlainSocketFactory.getSocketFactory(), 80));
		ThreadSafeClientConnManager manager = new ThreadSafeClientConnManager(params, registry);
		httpClient = new DefaultHttpClient(manager, params);
		//httpClient.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 30000);
	}

	
	//user supplied variables
	private String host = null;
	private int port = 80;
	private String path = null;
	private List<NameValuePair> query = null;
	private List<NameValuePair> post = null;
	private Handler handler = null;
	private HttpResponseWrapper callbackWrapper = null;
	private String scheme = "http";
	
	
	/**
	 * Used to setup a request to a url
	 * 
	 * @param host
	 * @param port
	 * @param path
	 * @param query
	 * @param post
	 * @param handler
	 * @param callbackWrapper
	 */
	private HttpUrlRequest(String scheme, String host, int port, String path, List<NameValuePair> query,  List<NameValuePair> post, Handler handler, HttpResponseWrapper callbackWrapper) {
		this.scheme = scheme;
		this.host = host;
		this.port = port;
		this.path = path;
		this.query = query;
		this.post = post;
		this.handler = handler;
		this.callbackWrapper = callbackWrapper;
	}

	
	

	/**
	 * Use this class if your class is implementing HttpResponseListener.
	 * Creates the request inside it's own Thread automatically.
	 * <b>run() is called automatically</b>
	 * 
	 * @param host
	 * @param port
	 * @param path
	 * @param queryString
	 * @param postData
	 * @param requestCode
	 * @param callback
	 * 
	 * @see HttpResponseListener
	 */
	static void sendRequest(String scheme, String host, int port, String path, List<NameValuePair> queryString, List<NameValuePair> postData, int requestCode, HttpResponseListener callback) {
		(new HttpUrlRequest(scheme, host, port, path, queryString, postData, new Handler(),new HttpResponseWrapper(callback,requestCode))).start();
	}
	
	
	/**
	 * Use this method if you want to control the Threading yourself.
	 * 
	 * @param host
	 * @param port
	 * @param path
	 * @param queryString
	 * @param postData
	 * @return
	 */
	static HttpResponse sendRequestForImmediateResponse(String scheme,String host, int port, String path, List<NameValuePair> queryString, List<NameValuePair> postData) {
		HttpUrlRequest req = new HttpUrlRequest(scheme, host, port, path, queryString, postData, null, null);
		return req.runInCurrentThread();
	}

	

	/**
	 * Runs the request in the current Thread, use this if you
	 * want to mananage Threading yourself through a thread pool etc.
	 * 
	 * @return HttpResponse
	 */
	private HttpResponse runInCurrentThread() {
		if(post==null) {
			return simpleGetRequest();
		} else {
			return simplePostRequest();
		}
	}




	@Override
	public void run() {
		//Determine the appropriate method to use
		if(post==null) {
			callbackWrapper.setResponse(simpleGetRequest());
			handler.post(callbackWrapper);
		} else {
			callbackWrapper.setResponse(simplePostRequest());
			handler.post(callbackWrapper);
		}
	}



	

	/**
	 * Send a GET request
	 * 
	 * @return HttpResponse or null if an exception occurred
	 * 
	 */
	private HttpResponse simpleGetRequest() {
		try {
			//Add lang to query string
			query.add(new BasicNameValuePair("lang", getLanguageInJoomlaFormat()));
			URI uri = URIUtils.createURI(scheme, host, port, path, URLEncodedUtils.format(query, HTTP.UTF_8), null);
			
			Log.d(TAG, uri.toString());
			
			//GET method
			HttpGet method = new HttpGet(uri);
			HttpResponse response = httpClient.execute(method);
			//HttpEntity entity = response.getEntity();

			if(response==null)
				return NullHttpResponse.INSTANCE;
			else
				return response;

		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (URISyntaxException e) {
			e.printStackTrace();
		}

		return NullHttpResponse.INSTANCE;
	}





	/**
	 * Send a POST request
	 * 
	 * 
	 * @return HttpResponse or null if an exception occurred
	 * 
	 */
	private HttpResponse simplePostRequest() {
		try {
			//Add lang to query string
			query.add(new BasicNameValuePair("lang", getLanguageInJoomlaFormat() ));

			URI uri = URIUtils.createURI(scheme, host, port, path, URLEncodedUtils.format(query, HTTP.UTF_8), null);
			
			Log.d(TAG, uri.toString());
			
			//POST method
			HttpPost postMethod=new HttpPost(uri);      
			postMethod.setEntity(new UrlEncodedFormEntity(post, HTTP.UTF_8));
			HttpResponse response = httpClient.execute(postMethod);
			//HttpEntity entity = response.getEntity();

			if(response==null)
				return NullHttpResponse.INSTANCE;
			else
				return response;

		} catch (UnsupportedEncodingException e) {
			Log.e(TAG, "UnsupportedEncodingException", e);
		} catch (ClientProtocolException e) {
			Log.e(TAG, "ClientProtocolException", e);
		} catch (IOException e) {
			Log.e(TAG, "IOException", e);
		} catch (URISyntaxException e) {
			Log.e(TAG, "URISyntaxException", e);
		}

		return NullHttpResponse.INSTANCE;
	}



	
	/**
	 * Converts the language code to correct Joomla format
	 * 
	 * @return language in the (en-GB)
	 */
	static String getLanguageInJoomlaFormat() {
		String joomlaName;
		String[] tokens = Locale.getDefault().toString().split("_");
		if (tokens.length >= 2 && tokens[1].length() == 2) {
		    joomlaName = tokens[0]+"-"+tokens[1];
		} else {
		    joomlaName = tokens[0]+"-"+tokens[0].toUpperCase();
		}
		return joomlaName;
	}

	
	
	
	
	/**
	 * Creates a null http response
	 * 
	 * @author Jack Matthews
	 *
	 */
	private enum NullHttpResponse implements HttpResponse {
		INSTANCE;

		@Override
		public HttpEntity getEntity() {
			return null;
		}

		@Override
		public Locale getLocale() {
			return null;
		}

		@Override
		public StatusLine getStatusLine() {
			return null;
		}

		@Override
		public void setEntity(HttpEntity entity) {

		}

		@Override
		public void setLocale(Locale loc) {

		}

		@Override
		public void setReasonPhrase(String reason) throws IllegalStateException {

		}

		@Override
		public void setStatusCode(int code) throws IllegalStateException {

		}

		@Override
		public void setStatusLine(StatusLine statusline) {

		}

		@Override
		public void setStatusLine(ProtocolVersion ver, int code) {

		}

		@Override
		public void setStatusLine(ProtocolVersion ver, int code, String reason) {

		}

		@Override
		public void addHeader(Header header) {

		}

		@Override
		public void addHeader(String name, String value) {

		}

		@Override
		public boolean containsHeader(String name) {
			return false;
		}

		@Override
		public Header[] getAllHeaders() {
			return null;
		}

		@Override
		public Header getFirstHeader(String name) {
			return null;
		}

		@Override
		public Header[] getHeaders(String name) {
			return null;
		}

		@Override
		public Header getLastHeader(String name) {
			return null;
		}

		@Override
		public HttpParams getParams() {
			return null;
		}

		@Override
		public ProtocolVersion getProtocolVersion() {
			return null;
		}

		@Override
		public HeaderIterator headerIterator() {
			return null;
		}

		@Override
		public HeaderIterator headerIterator(String name) {
			return null;
		}

		@Override
		public void removeHeader(Header header) {

		}

		@Override
		public void removeHeaders(String name) {

		}

		@Override
		public void setHeader(Header header) {

		}

		@Override
		public void setHeader(String name, String value) {

		}

		@Override
		public void setHeaders(Header[] headers) {

		}

		@Override
		public void setParams(HttpParams params) {

		}
	}

}
